<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>测试Gzip</title>
</head>
<body>
<div>
    <span style="font-size: 12px;color: darkgray">内容越长，重复率越高，压缩效果越好，如果字数过少，压缩率可能超过100%</span>
</div>
<textarea id="input" oninput="input()" rows="12" cols="100"></textarea>
<div>
    <strong>压缩率:</strong>
    <span id="ysl"></span>
</div>
<div style="display:none">
    <strong>原文:</strong>
    <span id="yw"></span>
</div>
<div>
    <strong>压缩:</strong>
    <span id="ys"></span>
</div>
<div>
    <strong>解压:</strong>
    <span id="jy"></span>
</div>
<hr/>
<div>
    <strong>压缩文件到base64: </strong>
    <input type="file" id="fileToBase64" accept=".txt">
</div>
<div>
    <strong>解压base64到文件: </strong>
    <button onclick="downloadFromBase64()">Download File</button><br/>
    <textarea id="base64Input" rows="12" cols="100"></textarea>
</div>
<hr/>
<div>
    <strong>压缩文件到gz: </strong>
    <input type="file" id="fileToGz">
</div>
<div>
    <strong>解压gz到文件: </strong>
    <input type="file" id="gzToFile" accept=".gz">
</div>

<script src="pako.min.js"></script>
<!--如果需要支持那些不自带atob btoa的浏览器，就需要用下面这个包来进行base64-->
<!--<script src="https://cdn.staticfile.org/Base64/1.0.2/base64.min.js"></script>-->
<script>
    function input() {
        const input = document.getElementById('input').value;
        const ys = zip(input);
        const jy = unzip(ys);
        document.getElementById('yw').innerText = input;
        document.getElementById('ys').innerText = ys;
        if (jy != input){
            document.getElementById('jy').innerText = "#######解压验证失败#######";
        } else {
            document.getElementById('jy').innerText = "解压验证成功!";
        }
        document.getElementById('ysl').innerHTML = length(input) + " => " +length(ys) + " <span style='color:#369'>" + (Math.round(length(ys) / length(input) * 10000) / 100.00 + "%") +"</span>" + (length(ys) > length(input)? " <span style='color:#963'>#压缩后大于压缩前#</span>" : "");

    }

    // 解压
    function unzip(b64Data) {
        let strData = atob(b64Data);
        const charData = strData.split('').map(function (x) {
            return x.charCodeAt(0);
        });
        const binData = new Uint8Array(charData);
        const data = pako.inflate(binData);
        strData = String.fromCharCode.apply(null, new Uint16Array(data));
        return decodeURIComponent(strData);
    }

    // 压缩
    function zip(str) {
        const binaryString = pako.gzip(encodeURIComponent(str), {to: 'string'})
        return btoa(binaryString);
    }

    // 占用字节数计算(UTF-8)
    function length(str) {
        let total = 0, charCode, i, len;
        for (i = 0, len = str.length; i < len; i++) {
            charCode = str.charCodeAt(i);
            if (charCode <= 0x007f) {
                total += 1;
            } else if (charCode <= 0x07ff) {
                total += 2;
            } else if (charCode <= 0xffff) {
                total += 3;
            } else {
                total += 4;
            }
        }
        return total;
    }
    
document.getElementById('fileToBase64').addEventListener('change', function(event) {
    const file = event.target.files[0];
    if (file) {
        const reader = new FileReader();
        reader.onload = function(e) {
            const binaryString = pako.gzip(e.target.result, {to: 'string'})
            document.getElementById('base64Input').innerText = btoa(binaryString);
        };
        reader.readAsText(file);
    }
});

function downloadFromBase64() {
    const base64String = document.getElementById('base64Input').value;
    const decodedString = atob(base64String);
    
    const charArray = decodedString.split('').map(char => char.charCodeAt(0));
    const byteArray = new Uint8Array(charArray);
    const decompressedText = pako.ungzip(byteArray, { to: 'string' });
    
    const blob = new Blob([decompressedText], { type: 'text/plain' });
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'downloaded.txt';
    document.body.appendChild(a);
    a.click();
    a.remove();
    window.URL.revokeObjectURL(url);
}
    
document.getElementById('fileToGz').addEventListener('change', function(event) {
    const file = event.target.files[0];
    if (file) {
        const reader = new FileReader();
        reader.onload = function(e) {
            const binaryString = pako.gzip(e.target.result, {to: 'string'})
            const blob = new Blob([binaryString], { type: 'application/gzip' });
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = file.name + '.gz';
            document.body.appendChild(a);
            a.click();
            a.remove();
            window.URL.revokeObjectURL(url);
        };
        reader.readAsText(file);
    }
});
    
document.getElementById('gzToFile').addEventListener('change', function(event) {
    const file = event.target.files[0];
    if (file) {
        const reader = new FileReader();
        reader.onload = function(e) {
            const binaryString = e.target.result;
            const charArray = binaryString.split('').map(char => char.charCodeAt(0));
            const byteArray = new Uint8Array(charArray);
            const decompressedText = pako.ungzip(byteArray, { to: 'string' });

            const blob = new Blob([decompressedText], { type: 'text/plain' });
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            var name = file.name.endsWith('.gz') ? file.name.slice(0, -3) : file.name;
            name = name.lastIndexOf('.') === -1 ? name + ".txt" : name;
            a.download = name;
            document.body.appendChild(a);
            a.click();
            a.remove();
            window.URL.revokeObjectURL(url);
        };
        reader.readAsText(file);
    }
});
</script>
</body>
</html>